Zorunlu DOM ve bileşen örneği manipülasyonu için React'in createRef'ini öğrenin. Sınıf bileşenlerinde odaklanma, medya ve üçüncü taraf entegrasyonları için ne zaman ve nasıl etkili bir şekilde kullanılacağını keşfedin.
React createRef: Bileşen ve DOM Elemanlarıyla Doğrudan Etkileşimler İçin Kapsamlı Rehber
Modern web geliştirmenin geniş ve genellikle karmaşık ortamında, React, kullanıcı arayüzleri oluşturmaya yönelik bildirimsel yaklaşımıyla öne çıkan baskın bir güç olarak ortaya çıkmıştır. Bu paradigma, geliştiricileri, doğrudan DOM manipülasyonları yoluyla bu görsel duruma nasıl ulaşacaklarını reçetelemek yerine, veriye dayalı olarak kullanıcı arayüzlerinin ne olması gerektiğini tanımlamaya teşvik eder. Bu soyutlama, kullanıcı arayüzü geliştirmeyi önemli ölçüde basitleştirmiş, uygulamaları daha öngörülebilir, anlaşılması daha kolay ve yüksek performanslı hale getirmiştir.
Ancak, web uygulamalarının gerçek dünyası nadiren tamamen bildirimseldir. Temeldeki DOM (Document Object Model) elemanıyla veya bir sınıf bileşeni örneğiyle doğrudan etkileşimin sadece uygun değil, aynı zamanda kesinlikle gerekli hale geldiği belirli, ancak yaygın senaryolar vardır. React'in bildirimsel akışından bu "kaçış kapıları" ref'ler olarak bilinir. React'in bu referansları oluşturmak ve yönetmek için sunduğu çeşitli mekanizmalar arasında, React.createRef(), özellikle sınıf bileşenleriyle çalışan geliştiriciler için temel bir API olarak durmaktadır.
Bu kapsamlı rehber, React.createRef()'i anlama, uygulama ve ustalaşma konusunda kesin kaynağınız olmayı amaçlamaktadır. Amacının ayrıntılı bir keşfine çıkacak, sözdizimi ve pratik uygulamalarına derinlemesine dalacak, en iyi uygulamalarını aydınlatacak ve onu diğer ref yönetimi stratejilerinden ayıracağız. İster zorunlu etkileşimler konusundaki anlayışınızı pekiştirmek isteyen deneyimli bir React geliştiricisi olun, ister bu önemli kavramı kavramak isteyen bir acemi olun, bu makale sizi modern kullanıcı deneyimlerinin karmaşık taleplerini zarif bir şekilde karşılayan daha sağlam, performanslı ve küresel olarak erişilebilir React uygulamaları oluşturmak için gereken bilgilerle donatacaktır.
React'te Ref'leri Anlamak: Bildirimsel ve Zorunlu Dünyalar Arasında Köprü Kurmak
React, özünde bildirimsel bir programlama stilini savunur. Bileşenlerinizi, durumlarını (state) ve nasıl render edileceklerini tanımlarsınız. React daha sonra devreye girer ve bildirdiğiniz kullanıcı arayüzünü yansıtmak için gerçek tarayıcı DOM'unu verimli bir şekilde günceller. Bu soyutlama katmanı son derece güçlüdür ve geliştiricileri doğrudan DOM manipülasyonunun karmaşıklıklarından ve performans tuzaklarından korur. React uygulamalarının genellikle bu kadar akıcı ve duyarlı hissetmesinin nedeni budur.
Tek Yönlü Veri Akışı ve Sınırları
React'in mimari gücü, tek yönlü veri akışında yatar. Veri, ebeveyn bileşenlerden alt bileşenlere prop'lar aracılığıyla öngörülebilir bir şekilde aşağı doğru akar ve bir bileşen içindeki durum değişiklikleri, alt ağacı boyunca yayılan yeniden render'ları tetikler. Bu model öngörülebilirliği teşvik eder ve hata ayıklamayı önemli ölçüde kolaylaştırır, çünkü verinin nereden kaynaklandığını ve kullanıcı arayüzünü nasıl etkilediğini her zaman bilirsiniz. Ancak, her etkileşim bu yukarıdan aşağıya veri akışıyla mükemmel bir şekilde uyumlu değildir.
Şu gibi senaryoları düşünün:
- Bir kullanıcı bir forma gittiğinde bir giriş alanına programatik olarak odaklanmak.
- Bir
<video>elemanındaplay()veyapause()metotlarını tetiklemek. - Düzeni dinamik olarak ayarlamak için render edilmiş bir
<div>'in tam piksel boyutlarını ölçmek. - Bir DOM konteynerine doğrudan erişim bekleyen karmaşık bir üçüncü taraf JavaScript kütüphanesini (örneğin, D3.js gibi bir grafik kütüphanesi veya bir harita görselleştirme aracı) entegre etmek.
Bu eylemler doğası gereği zorunludur – sadece istenen durumu bildirmek yerine, bir elemana doğrudan bir şey yapmasını emretmeyi içerirler. React'in bildirimsel modeli genellikle birçok zorunlu detayı soyutlayabilse de, onlara olan ihtiyacı tamamen ortadan kaldırmaz. İşte tam da bu noktada ref'ler devreye girer ve bu doğrudan etkileşimleri gerçekleştirmek için kontrollü bir kaçış kapısı sağlar.
Ref'ler Ne Zaman Kullanılır: Zorunlu ve Bildirimsel Etkileşimler Arasında Gezinmek
Ref'lerle çalışırken en önemli ilke, onları idareli ve yalnızca kesinlikle gerekli olduğunda kullanmaktır. Bir görev React'in standart bildirimsel mekanizmaları (state ve prop'lar) kullanılarak gerçekleştirilebiliyorsa, bu her zaman tercih ettiğiniz yaklaşım olmalıdır. Ref'lere aşırı güvenmek, anlaşılması, bakımı ve hata ayıklaması daha zor olan kodlara yol açabilir ve React'in sağladığı faydaları baltalayabilir.
Ancak, gerçekten bir DOM düğümüne veya bir bileşen örneğine doğrudan erişim gerektiren durumlar için ref'ler doğru ve amaçlanan çözümdür. İşte uygun kullanım durumlarının daha ayrıntılı bir dökümü:
- Odak, Metin Seçimi ve Medya Oynatımını Yönetme: Bunlar, elemanlarla zorunlu olarak etkileşimde bulunmanız gereken klasik örneklerdir. Sayfa yüklendiğinde bir arama çubuğuna otomatik odaklanmayı, bir giriş alanındaki tüm metni seçmeyi veya bir ses veya video oynatıcının oynatımını kontrol etmeyi düşünün. Bu eylemler genellikle sadece prop'ları veya state'i değiştirerek değil, kullanıcı olayları veya bileşen yaşam döngüsü metotları tarafından tetiklenir.
- Zorunlu Animasyonları Tetikleme: Birçok animasyon CSS geçişleri/animasyonları veya React animasyon kütüphaneleri ile bildirimsel olarak yönetilebilse de, özellikle HTML Canvas API, WebGL içeren veya React'in render döngüsü dışında en iyi yönetilen eleman özellikleri üzerinde ince taneli kontrol gerektiren bazı karmaşık, yüksek performanslı animasyonlar ref'leri gerektirebilir.
- Üçüncü Taraf DOM Kütüphaneleriyle Entegrasyon: Birçok saygın JavaScript kütüphanesi (örneğin, D3.js, haritalar için Leaflet, çeşitli eski kullanıcı arayüzü araç setleri) belirli DOM elemanlarını doğrudan manipüle etmek için tasarlanmıştır. Ref'ler, React'in bir konteyner elemanı render etmesine ve ardından üçüncü taraf kütüphanesine kendi zorunlu render mantığı için o konteynere erişim izni vermesine olanak tanıyarak temel köprüyü sağlar.
-
Eleman Boyutlarını veya Konumunu Ölçme: Gelişmiş düzenler, sanallaştırma veya özel kaydırma davranışları uygulamak için, genellikle bir elemanın boyutu, viewport'a göre konumu veya kaydırma yüksekliği hakkında kesin bilgilere ihtiyacınız vardır.
getBoundingClientRect()gibi API'lere yalnızca gerçek DOM düğümlerinde erişilebilir, bu da bu tür hesaplamalar için ref'leri vazgeçilmez kılar.
Tersine, bildirimsel olarak başarılabilecek görevler için ref kullanmaktan kaçınmalısınız. Bu şunları içerir:
- Bir bileşenin stilini değiştirmek (koşullu stil için state kullanın).
- Bir elemanın metin içeriğini değiştirmek (prop olarak geçin veya state'i güncelleyin).
- Karmaşık bileşen iletişimi (prop'lar ve callback'ler genellikle daha üstündür).
- State yönetiminin işlevselliğini taklit etmeye çalıştığınız herhangi bir senaryo.
React.createRef() Detaylı Bakış: Sınıf Bileşenleri İçin Modern Yaklaşım
React.createRef(), React 16.3'te tanıtıldı ve string ref'ler (artık kullanımdan kaldırıldı) ve callback ref'ler (hala geçerli ancak genellikle daha ayrıntılı) gibi eski yöntemlere kıyasla ref'leri yönetmek için daha açık ve temiz bir yol sağladı. Sınıf yapısı içinde doğal olarak yer alan nesne yönelimli bir API sunarak, sınıf bileşenleri için birincil ref oluşturma mekanizması olarak tasarlanmıştır.
Sözdizimi ve Temel Kullanım: Üç Adımlı Bir Süreç
createRef() kullanma iş akışı basittir ve üç temel adımı içerir:
-
Bir Ref Nesnesi Oluşturun: Sınıf bileşeninizin constructor'ında,
React.createRef()çağrısı yaparak bir ref örneği başlatın ve geri dönüş değerini bir örnek özelliğine (örneğin,this.myRef) atayın. -
Ref'i Ekleyin: Bileşeninizin
rendermetodunda, oluşturulan ref nesnesini referanslamak istediğiniz React elemanının (bir HTML elemanı veya bir sınıf bileşeni)refözelliğine geçin. -
Hedefe Erişin: Bileşen mount edildikten sonra, referanslanan DOM düğümü veya bileşen örneği, ref nesnenizin
.currentözelliği aracılığıyla (örneğin,this.myRef.current) kullanılabilir olacaktır.
import React from 'react';
class FocusInputOnMount extends React.Component {
constructor(props) {
super(props);
this.inputElementRef = React.createRef(); // Adım 1: Constructor'da bir ref nesnesi oluşturun
console.log('Constructor: Ref current değeri başlangıçta:', this.inputElementRef.current); // null
}
componentDidMount() {
if (this.inputElementRef.current) {
this.inputElementRef.current.focus();
console.log('ComponentDidMount: Input odaklandı. Mevcut değer:', this.inputElementRef.current.value);
}
}
handleButtonClick = () => {
if (this.inputElementRef.current) {
alert(`Input değeri: ${this.inputElementRef.current.value}`);
}
};
render() {
console.log('Render: Ref current değeri:', this.inputElementRef.current); // İlk render'da hala null
return (
<div style={{ padding: '20px', border: '1px solid #ccc', borderRadius: '8px' }}>
<h3>Otomatik Odaklanan Giriş Alanı</h3>
<label htmlFor="focusInput">Adınızı girin:</label><br />
<input
id="focusInput"
type="text"
ref={this.inputElementRef} // Adım 2: Ref'i <input> elemanına ekleyin
placeholder="Adınız buraya..."
style={{ margin: '10px 0', padding: '8px', borderRadius: '4px', border: '1px solid #ddd' }}
/><br />
<button
onClick={this.handleButtonClick}
style={{ padding: '10px 15px', background: '#007bff', color: 'white', border: 'none', borderRadius: '5px', cursor: 'pointer' }}
>
Input Değerini Göster
</button>
<p><em>Bu giriş alanı bileşen yüklendiğinde otomatik olarak odaklanacaktır.</em></p>
</div>
);
}
}
Bu örnekte, this.inputElementRef React'in dahili olarak yöneteceği bir nesnedir. <input> elemanı render edilip DOM'a mount edildiğinde, React o gerçek DOM düğümünü this.inputElementRef.current'a atar. componentDidMount yaşam döngüsü metodu, bileşenin ve alt elemanlarının DOM'a render edildiğini ve .current özelliğinin kullanılabilir ve doldurulmuş olduğunu garanti ettiği için ref'lerle etkileşim kurmak için ideal bir yerdir.
Ref'i Bir DOM Elemanına Eklemek: Doğrudan DOM Erişimi
Bir ref'i standart bir HTML elemanına (örneğin, <div>, <p>, <button>, <img>) eklediğinizde, ref nesnenizin .current özelliği gerçek altta yatan DOM elemanını tutacaktır. Bu size tüm standart tarayıcı DOM API'lerine sınırsız erişim sağlar ve genellikle React'in bildirimsel kontrolü dışında olan eylemleri gerçekleştirmenize olanak tanır. Bu, çeşitli kullanıcı ortamları ve cihaz türleri arasında hassas düzen, kaydırma veya odak yönetiminin kritik olabileceği küresel uygulamalar için özellikle kullanışlıdır.
import React from 'react';
class ScrollToElementExample extends React.Component {
constructor(props) {
super(props);
this.targetDivRef = React.createRef();
this.state = { showScrollButton: false };
}
componentDidMount() {
// Kaydırma düğmesini yalnızca kaydırılacak kadar içerik varsa göster
// Bu kontrol aynı zamanda ref'in zaten güncel (current) olduğunu da sağlar.
if (this.targetDivRef.current && window.innerHeight < document.body.scrollHeight) {
this.setState({ showScrollButton: true });
}
}
handleScrollToTarget = () => {
if (this.targetDivRef.current) {
// Akıcı kaydırma için global olarak tarayıcılar tarafından geniş çapta desteklenen scrollIntoView kullanılıyor.
this.targetDivRef.current.scrollIntoView({
behavior: 'smooth', // Daha iyi bir kullanıcı deneyimi için kaydırmayı canlandırır
block: 'start' // Elemanın üstünü viewport'un üstüne hizalar
});
console.log('Hedef div'e kaydırıldı!');
} else {
console.warn('Hedef div henüz kaydırma için mevcut değil.');
}
};
render() {
return (
<div style={{ padding: '15px' }}>
<h2>Ref ile Belirli Bir Elemana Kaydırma</h2>
<p>Bu örnek, ekran dışında olan bir DOM elemanına programatik olarak nasıl kaydırılacağını gösterir.</p>
{this.state.showScrollButton && (
<button
onClick={this.handleScrollToTarget}
style={{ marginBottom: '20px', padding: '10px 20px', background: '#28a745', color: 'white', border: 'none', borderRadius: '5px', cursor: 'pointer' }}
>
Hedef Alana Aşağı Kaydır
</button>
)}
<div style={{ height: '1500px', background: '#f8f9fa', padding: '20px', marginBottom: '20px', border: '1px dashed #6c757d' }}>
<p>Dikey kaydırma alanı oluşturmak için yer tutucu içerik.</p>
<p>Kullanıcıların geniş içeriğe göz atmasını gerektiren uzun makaleleri, karmaşık formları veya ayrıntılı panoları hayal edin. Programatik kaydırma, kullanıcıların manuel çaba olmadan ilgili bölümlere hızlı bir şekilde ulaşmasını sağlar, bu da tüm cihazlarda ve ekran boyutlarında erişilebilirliği ve kullanıcı akışını iyileştirir.</p>
<p>Bu teknik, çok sayfalı formlarda, adım adım sihirbazlarda veya derin gezinmeli tek sayfa uygulamalarında özellikle kullanışlıdır.</p>
</div>
<div
ref={this.targetDivRef} // Ref'i buraya ekleyin
style={{
minHeight: '300px',
background: '#e9ecef',
padding: '30px',
border: '2px solid #007bff',
borderRadius: '10px',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
textAlign: 'center'
}}
>
<h3>Hedef alana ulaştınız!</h3>
<p>Burası programatik olarak kaydırdığımız bölüm.</p>
<p>Kaydırma davranışını hassas bir şekilde kontrol etme yeteneği, özellikle ekran alanının sınırlı olduğu ve hassas gezinmenin çok önemli olduğu mobil cihazlarda kullanıcı deneyimini geliştirmek için kritiktir.</p>
</div>
</div>
);
}
}
Bu örnek, createRef'in tarayıcı düzeyindeki etkileşimler üzerinde nasıl kontrol sağladığını güzel bir şekilde göstermektedir. Bu tür programatik kaydırma yetenekleri, uzun belgelerde gezinmekten kullanıcıları karmaşık iş akışlarında yönlendirmeye kadar birçok uygulamada kritiktir. scrollIntoView'deki behavior: 'smooth' seçeneği, evrensel olarak kullanıcı deneyimini geliştiren hoş, animasyonlu bir geçiş sağlar.
Ref'i Bir Sınıf Bileşenine Eklemek: Örneklerle (Instance) Etkileşim
Yerel DOM elemanlarının ötesinde, bir ref'i bir sınıf bileşeni örneğine de ekleyebilirsiniz. Bunu yaptığınızda, ref nesnenizin .current özelliği, gerçek somutlaştırılmış sınıf bileşeninin kendisini tutacaktır. Bu, bir ebeveyn bileşenin, alt sınıf bileşeni içinde tanımlanan metotları doğrudan çağırmasına veya örnek özelliklerine erişmesine olanak tanır. Güçlü olmasına rağmen, bu yetenek aşırı dikkatle kullanılmalıdır, çünkü geleneksel tek yönlü veri akışını kırmaya izin verir ve potansiyel olarak daha az öngörülebilir uygulama davranışına yol açar.
import React from 'react';
// Alt Sınıf Bileşeni
class DialogBox extends React.Component {
constructor(props) {
super(props);
this.state = { isOpen: false, message: '' };
}
// Ref aracılığıyla ebeveyne sunulan metot
open(message) {
this.setState({ isOpen: true, message });
}
close = () => {
this.setState({ isOpen: false, message: '' });
};
render() {
if (!this.state.isOpen) return null;
return (
<div style={{
position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)',
padding: '25px 35px', background: 'white', border: '1px solid #ddd', borderRadius: '8px',
boxShadow: '0 5px 15px rgba(0,0,0,0.2)', zIndex: 1000, maxWidth: '400px', width: '90%', textAlign: 'center'
}}>
<h4>Ebeveynden Gelen Mesaj</h4>
<p>{this.state.message}</p>
<button
onClick={this.close}
style={{ marginTop: '15px', padding: '8px 15px', background: '#dc3545', color: 'white', border: 'none', borderRadius: '5px', cursor: 'pointer' }}
>
Kapat
</button>
</div>
);
}
}
// Ebeveyn Sınıf Bileşeni
class AppWithDialog extends React.Component {
constructor(props) {
super(props);
this.dialogRef = React.createRef();
}
handleOpenDialog = () => {
if (this.dialogRef.current) {
// Alt bileşen örneğine erişin ve 'open' metodunu çağırın
this.dialogRef.current.open('Merhaba ebeveyn bileşenden! Bu diyalog zorunlu olarak açıldı.');
}
};
render() {
return (
<div style={{ padding: '20px', textAlign: 'center' }}>
<h2>Ref ile Ebeveyn-Çocuk İletişimi</h2>
<p>Bu, bir ebeveyn bileşenin, alt sınıf bileşeninin bir metodunu zorunlu olarak nasıl kontrol edebileceğini gösterir.</p>
<button
onClick={this.handleOpenDialog}
style={{ padding: '12px 25px', background: '#007bff', color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer', fontSize: '1.1em' }}
>
Zorunlu Diyaloğu Aç
</button>
<DialogBox ref={this.dialogRef} /> // Ref'i bir sınıf bileşeni örneğine ekleyin
</div>
);
}
}
Burada, AppWithDialog ref'i aracılığıyla DialogBox bileşeninin open metodunu doğrudan çağırabilir. Bu desen, bir modal gösterme, bir formu sıfırlama veya bir alt bileşen içinde kapsüllenmiş harici UI elemanlarını programatik olarak kontrol etme gibi eylemleri tetiklemek için kullanışlı olabilir. Ancak, çoğu senaryo için prop tabanlı iletişimi tercih etmek, açık ve öngörülebilir bir veri akışını sürdürmek için ebeveynden çocuğa veri ve callback'ler geçmek genellikle önerilir. Sadece bu eylemler gerçekten zorunlu olduğunda ve tipik prop/state akışına uymadığında alt bileşen metotları için ref'lere başvurun.
Ref'i Bir Fonksiyonel Bileşene Eklemek (Önemli Bir Ayrım)
Yaygın bir yanılgı ve önemli bir ayrım noktası, createRef() kullanarak bir ref'i doğrudan bir fonksiyonel bileşene ekleyememenizdir. Fonksiyonel bileşenler, doğaları gereği, sınıf bileşenlerinin sahip olduğu şekilde örneklere sahip değildir. Bir ref'i doğrudan bir fonksiyonel bileşene atamaya çalışırsanız (örneğin, <MyFunctionalComponent ref={this.myRef} />), React geliştirme modunda bir uyarı verir çünkü .current'a atanacak bir bileşen örneği yoktur.
Amacınız bir ebeveyn bileşenin (createRef kullanan bir sınıf bileşeni veya useRef kullanan bir fonksiyonel bileşen olabilir) bir fonksiyonel alt bileşen içinde render edilen bir DOM elemanına erişmesini sağlamaksa, React.forwardRef kullanmalısınız. Bu üst düzey bileşen, fonksiyonel bileşenlerin kendi içlerindeki belirli bir DOM düğümüne veya zorunlu bir handle'a bir ref sunmasına olanak tanır.
Alternatif olarak, bir fonksiyonel bileşen içinde çalışıyorsanız ve bir ref oluşturup yönetmeniz gerekiyorsa, uygun mekanizma daha sonraki bir karşılaştırma bölümünde kısaca tartışılacak olan useRef hook'udur. createRef'in temel olarak sınıf bileşenlerine ve onların örnek tabanlı doğasına bağlı olduğunu hatırlamak hayati önem taşır.
DOM Düğümüne veya Bileşen Örneğine Erişmek: `.current` Özelliği Açıklandı
Ref etkileşiminin özü, React.createRef() tarafından oluşturulan ref nesnesinin .current özelliği etrafında döner. Yaşam döngüsünü ve ne tutabileceğini anlamak, etkili ref yönetimi için çok önemlidir.
`.current` Özelliği: Zorunlu Kontrol için Geçidiniz
.current özelliği, React'in yönettiği değiştirilebilir bir nesnedir. Referanslanan eleman veya bileşen örneğine doğrudan bağlantı görevi görür. Değeri, bileşenin yaşam döngüsü boyunca değişir:
-
Başlatma: Constructor'da ilk olarak
React.createRef()'i çağırdığınızda, ref nesnesi oluşturulur ve.currentözelliğinullolarak başlatılır. Bunun nedeni, bu aşamada bileşenin henüz render edilmemiş olması ve ref'in işaret edebileceği bir DOM elemanı veya bileşen örneğinin mevcut olmamasıdır. -
Mount Etme: Bileşen DOM'a render edildiğinde ve
refözelliğine sahip eleman oluşturulduğunda, React gerçek DOM düğümünü veya sınıf bileşeni örneğini ref nesnenizin.currentözelliğine atar. Bu genelliklerendermetodu tamamlandıktan hemen sonra vecomponentDidMountçağrılmadan önce gerçekleşir. Bu nedenle,componentDidMount,.current'a erişmek ve onunla etkileşim kurmak için en güvenli ve en yaygın yerdir. -
Unmount Etme: Bileşen DOM'dan unmount edildiğinde, React
.currentözelliğini otomatik olaraknull'a geri ayarlar. Bu, bellek sızıntılarını önlemek ve uygulamanızın artık DOM'da var olmayan elemanlara referans tutmamasını sağlamak için kritiktir. -
Güncelleme: Bir güncelleme sırasında bir elemanın
refözelliği değiştirilirse, nadir durumlarda, eski ref'incurrentözelliği, yeni ref'incurrentözelliği ayarlanmadan öncenullolarak ayarlanır. Bu davranış daha az yaygındır ancak karmaşık dinamik ref atamaları için not etmek önemlidir.
import React from 'react';
class RefLifecycleLogger extends React.Component {
constructor(props) {
super(props);
this.myDivRef = React.createRef();
console.log('1. Constructor: this.myDivRef.current değeri', this.myDivRef.current); // null
}
componentDidMount() {
console.log('3. componentDidMount: this.myDivRef.current değeri', this.myDivRef.current); // Gerçek DOM elemanı
if (this.myDivRef.current) {
this.myDivRef.current.style.backgroundColor = '#d4edda'; // Gösterim için zorunlu stil verme
this.myDivRef.current.innerText += ' - Ref aktif!';
}
}
componentDidUpdate(prevProps, prevState) {
console.log('4. componentDidUpdate: this.myDivRef.current değeri', this.myDivRef.current); // Gerçek DOM elemanı (güncellemelerden sonra)
}
componentWillUnmount() {
console.log('5. componentWillUnmount: this.myDivRef.current değeri', this.myDivRef.current); // Gerçek DOM elemanı (null yapılmadan hemen önce)
// Bu noktada, gerekirse temizlik yapabilirsiniz
}
render() {
// İlk render sırasında, this.myDivRef.current hala null'dır çünkü DOM henüz oluşturulmamıştır.
// Sonraki render'larda (mount işleminden sonra), elemanı tutacaktır.
console.log('2. Render: this.myDivRef.current değeri', this.myDivRef.current);
return (
<div
ref={this.myDivRef}
style={{ padding: '20px', border: '1px solid #28a745', margin: '20px', minHeight: '80px', display: 'flex', alignItems: 'center' }}
>
<p>Burası kendisine bir ref eklenmiş bir div.</p>
</div>
);
}
}
RefLifecycleLogger için konsol çıktısını gözlemlemek, this.myDivRef.current'ın ne zaman kullanılabilir hale geldiğine dair net bir fikir verir. Özellikle mount edilmeden önce veya unmount edildikten sonra çalışabilecek metotlarda, onunla etkileşim kurmaya çalışmadan önce this.myDivRef.current'ın null olmadığını her zaman kontrol etmek çok önemlidir.
`.current` Neleri Tutabilir? Ref'inizin İçeriğini Keşfetmek
current'ın tuttuğu değerin türü, ref'i neye eklediğinize bağlıdır:
-
Bir HTML elemanına eklendiğinde (örneğin,
<div>,<input>):.currentözelliği, gerçek altta yatan DOM elemanını içerecektir. Bu, tam DOM API yelpazesine erişim sağlayan yerel bir JavaScript nesnesidir. Örneğin, bir ref'i bir<input type="text">'e eklerseniz,.currentbirHTMLInputElementnesnesi olacak ve.focus()gibi metotları çağırmanıza,.valuegibi özellikleri okumanıza veya.placeholdergibi nitelikleri değiştirmenize olanak tanıyacaktır. Bu, ref'lerin en yaygın kullanım durumudur.this.inputRef.current.focus();
this.videoRef.current.play();
const { width, height } = this.divRef.current.getBoundingClientRect(); -
Bir sınıf bileşenine eklendiğinde (örneğin,
<MyClassComponent />):.currentözelliği, o sınıf bileşeninin örneğini tutacaktır. Bu, o alt bileşen içinde tanımlanan metotları doğrudan çağırabileceğiniz (örneğin,childRef.current.someMethod()) veya hatta durumuna veya prop'larına erişebileceğiniz anlamına gelir (ancak bir alt bileşenden ref aracılığıyla doğrudan state/prop'lara erişmek genellikle prop'lar ve state güncellemeleri lehine önerilmez). Bu yetenek, standart prop tabanlı etkileşim modeline uymayan alt bileşenlerde belirli davranışları tetiklemek için güçlüdür.this.childComponentRef.current.resetForm();
// Nadiren, ama mümkün: console.log(this.childComponentRef.current.state.someValue); -
Bir fonksiyonel bileşene eklendiğinde (
forwardRefaracılığıyla): Daha önce belirtildiği gibi, ref'ler doğrudan fonksiyonel bileşenlere eklenemez. Ancak, bir fonksiyonel bileşenReact.forwardRefile sarmalanmışsa,.currentözelliği, fonksiyonel bileşenin iletilen ref aracılığıyla açıkça ortaya çıkardığı değeri tutacaktır. Bu genellikle fonksiyonel bileşen içindeki bir DOM elemanı veya zorunlu metotlar içeren bir nesnedir (forwardRefile birlikteuseImperativeHandlehook'u kullanılarak).// Ebeveynde, myForwardedRef.current açığa çıkarılan DOM düğümü veya nesnesi olacaktır
this.myForwardedRef.current.focus();
this.myForwardedRef.current.customResetMethod();
`createRef` için Pratik Kullanım Senaryoları
React.createRef()'in faydasını gerçekten kavramak için, basit odak yönetiminin ötesine geçen, vazgeçilmez olduğunu kanıtlayan daha ayrıntılı, küresel olarak ilgili senaryoları keşfedelim.
1. Kültürler Arasında Odak, Metin Seçimi veya Medya Oynatımını Yönetme
Bunlar, zorunlu kullanıcı arayüzü etkileşimlerinin başlıca örnekleridir. Küresel bir kitle için tasarlanmış çok adımlı bir form düşünün. Bir kullanıcı bir bölümü tamamladıktan sonra, dil veya varsayılan metin yönü (Soldan Sağa veya Sağdan Sola) ne olursa olsun, bir sonraki bölümün ilk girişine otomatik olarak odaklanmak isteyebilirsiniz. Ref'ler gerekli kontrolü sağlar.
import React from 'react';
class DynamicFocusForm extends React.Component {
constructor(props) {
super(props);
this.firstNameRef = React.createRef();
this.lastNameRef = React.createRef();
this.emailRef = React.createRef();
this.state = { currentStep: 1 };
}
componentDidMount() {
// Bileşen mount olduğunda ilk girişe odaklan
this.firstNameRef.current.focus();
}
handleNextStep = (nextRef) => {
this.setState(prevState => ({ currentStep: prevState.currentStep + 1 }), () => {
// State güncellendikten ve bileşen yeniden render edildikten sonra, bir sonraki girişe odaklan
if (nextRef.current) {
nextRef.current.focus();
}
});
};
render() {
const { currentStep } = this.state;
const formSectionStyle = { border: '1px solid #0056b3', padding: '20px', margin: '15px 0', borderRadius: '8px', background: '#e7f0fa' };
const inputStyle = { width: '100%', padding: '10px', margin: '8px 0', border: '1px solid #ccc', borderRadius: '4px' };
const buttonStyle = { padding: '10px 20px', background: '#007bff', color: 'white', border: 'none', borderRadius: '5px', cursor: 'pointer', marginTop: '10px' };
return (
<div style={{ maxWidth: '600px', margin: '30px auto', padding: '25px', boxShadow: '0 4px 12px rgba(0,0,0,0.1)', borderRadius: '10px', background: 'white' }}>
<h2>Ref Yönetimli Odaklı Çok Adımlı Form</h2>
<p>Mevcut Adım: <strong>{currentStep}</strong></p>
{currentStep === 1 && (
<div style={formSectionStyle}>
<h3>Kişisel Detaylar</h3>
<label htmlFor="firstName">Ad:</label>
<input id="firstName" type="text" ref={this.firstNameRef} style={inputStyle} placeholder="örn., Ali" />
<label htmlFor="lastName">Soyad:</label>
<input id="lastName" type="text" ref={this.lastNameRef} style={inputStyle} placeholder="örn., Yılmaz" />
<button onClick={() => this.handleNextStep(this.emailRef)} style={buttonStyle}>Sonraki →</button>
</div>
)}
{currentStep === 2 && (
<div style={formSectionStyle}>
<h3>İletişim Bilgileri</h3>
<label htmlFor="email">E-posta:</label>
<input id="email" type="email" ref={this.emailRef} style={inputStyle} placeholder="örn., ali.yilmaz@example.com" />
<p>... diğer iletişim alanları ...</p>
<button onClick={() => alert('Form Gönderildi!')} style={buttonStyle}>Gönder</button>
</div>
)}
<p><em>Bu etkileşim, özellikle klavye navigasyonuna veya yardımcı teknolojilere dayanan küresel kullanıcılar için erişilebilirliği ve kullanıcı deneyimini önemli ölçüde artırır.</em></p>
</div>
);
}
}
Bu örnek, createRef'in odaklanmayı programatik olarak yönetmek için kullanıldığı pratik bir çok adımlı formu göstermektedir. Bu, çeşitli dil ve kültür bağlamlarında kullanılan uygulamalar için kritik bir husus olan sorunsuz ve erişilebilir bir kullanıcı yolculuğu sağlar. Benzer şekilde, medya oynatıcılar için, ref'ler, HTML5 <video> veya <audio> elemanlarının yerel API'leriyle doğrudan etkileşim kuran özel kontroller (oynat, duraklat, ses, arama) oluşturmanıza olanak tanır ve tarayıcı varsayılanlarından bağımsız tutarlı bir deneyim sunar.
2. Zorunlu Animasyonları ve Kanvas Etkileşimlerini Tetikleme
Bildirimsel animasyon kütüphaneleri birçok kullanıcı arayüzü efekti için mükemmel olsa da, özellikle HTML5 Canvas API, WebGL'den yararlanan veya React'in render döngüsü dışında en iyi yönetilen eleman özellikleri üzerinde ince taneli kontrol gerektiren bazı gelişmiş animasyonlar, ref'lerden büyük ölçüde yararlanır. Örneğin, bir Kanvas elemanı üzerinde gerçek zamanlı bir veri görselleştirmesi veya bir oyun oluşturmak, doğası gereği zorunlu bir süreç olan bir piksel tamponuna doğrudan çizim yapmayı içerir.
import React from 'react';
class CanvasAnimator extends React.Component {
constructor(props) {
super(props);
this.canvasRef = React.createRef();
this.animationFrameId = null;
}
componentDidMount() {
this.startAnimation();
}
componentWillUnmount() {
this.stopAnimation();
}
startAnimation = () => {
const canvas = this.canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
let angle = 0;
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const radius = 50;
const animate = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height); // Kanvası temizle
// Dönen bir kare çiz
ctx.save();
ctx.translate(centerX, centerY);
ctx.rotate(angle);
ctx.fillStyle = '#6f42c1';
ctx.fillRect(-radius / 2, -radius / 2, radius, radius);
ctx.restore();
angle += 0.05; // Dönüş için açıyı artır
this.animationFrameId = requestAnimationFrame(animate);
};
this.animationFrameId = requestAnimationFrame(animate);
};
stopAnimation = () => {
if (this.animationFrameId) {
cancelAnimationFrame(this.animationFrameId);
}
};
render() {
return (
<div style={{ textAlign: 'center', margin: '30px auto', border: '1px solid #ced4da', padding: '20px', borderRadius: '8px', background: '#f8f9fa' }}>
<h3>createRef ile Zorunlu Kanvas Animasyonu</h3>
<p>Bu kanvas animasyonu, bir ref aracılığıyla doğrudan tarayıcı API'leri kullanılarak kontrol edilir.</p>
<canvas ref={this.canvasRef} width="300" height="200" style={{ border: '1px solid #adb5bd', background: 'white' }}>
Tarayıcınız HTML5 kanvas etiketini desteklemiyor.
</canvas>
<p><em>Böyle doğrudan bir kontrol, dünya çapında çeşitli endüstrilerde kullanılan yüksek performanslı grafikler, oyunlar veya özel veri görselleştirmeleri için hayati önem taşır.</em></p>
</div>
);
}
}
Bu bileşen bir kanvas elemanı sağlar ve 2D render bağlamına doğrudan erişim sağlamak için bir ref kullanır. `requestAnimationFrame` tarafından desteklenen animasyon döngüsü, daha sonra zorunlu olarak dönen bir kare çizer ve günceller. Bu desen, kullanıcının coğrafi konumu veya cihaz yeteneklerinden bağımsız olarak hassas, kare kare render gerektiren etkileşimli veri panoları, çevrimiçi tasarım araçları veya hatta basit oyunlar oluşturmak için temeldir.
3. Üçüncü Taraf DOM Kütüphaneleriyle Entegrasyon: Sorunsuz Bir Köprü
Ref kullanmanın en çekici nedenlerinden biri, React'i doğrudan DOM'u manipüle eden harici JavaScript kütüphaneleriyle entegre etmektir. Birçok güçlü kütüphane, özellikle eskileri veya belirli render görevlerine odaklananlar (grafik, haritalama veya zengin metin düzenleme gibi), bir DOM elemanını hedef alarak ve ardından içeriğini kendileri yöneterek çalışır. React, bildirimsel modunda, aynı DOM alt ağacını kontrol etmeye çalışarak bu kütüphanelerle çakışırdı. Ref'ler, harici kütüphane için belirlenmiş bir 'konteyner' sağlayarak bu çakışmayı önler.
import React from 'react';
import * as d3 from 'd3'; // D3.js'in kurulu ve içe aktarıldığını varsayarak
class D3BarChart extends React.Component {
constructor(props) {
super(props);
this.chartContainerRef = React.createRef();
}
// Bileşen mount olduğunda grafiği çiz
componentDidMount() {
this.drawChart();
}
// Bileşen güncellendiğinde (örneğin, props.data değiştiğinde), grafiği güncelle
componentDidUpdate(prevProps) {
if (prevProps.data !== this.props.data) {
this.drawChart();
}
}
// Bileşen unmount olduğunda, bellek sızıntılarını önlemek için D3 elemanlarını temizle
componentWillUnmount() {
d3.select(this.chartContainerRef.current).selectAll('*').remove();
}
drawChart = () => {
const data = this.props.data || [40, 80, 20, 100, 60, 90]; // Varsayılan veri
const node = this.chartContainerRef.current;
if (!node) return; // Ref'in kullanılabilir olduğundan emin ol
// D3 tarafından çizilen önceki grafik elemanlarını temizle
d3.select(node).selectAll('*').remove();
const margin = { top: 20, right: 20, bottom: 30, left: 40 };
const width = 460 - margin.left - margin.right;
const height = 300 - margin.top - margin.bottom;
const svg = d3.select(node)
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
// Ölçekleri ayarla
const x = d3.scaleBand()
.range([0, width])
.padding(0.1);
const y = d3.scaleLinear()
.range([height, 0]);
x.domain(data.map((d, i) => i)); // Basitlik için alan olarak dizin kullan
y.domain([0, d3.max(data)]);
// Çubukları ekle
svg.selectAll('.bar')
.data(data)
.enter().append('rect')
.attr('class', 'bar')
.attr('x', (d, i) => x(i))
.attr('width', x.bandwidth())
.attr('y', d => y(d))
.attr('height', d => height - y(d))
.attr('fill', '#17a2b8');
// X Eksenini Ekle
svg.append('g')
.attr('transform', `translate(0,${height})`)
.call(d3.axisBottom(x));
// Y Eksenini Ekle
svg.append('g')
.call(d3.axisLeft(y));
};
render() {
return (
<div style={{ textAlign: 'center', margin: '30px auto', border: '1px solid #00a0b2', padding: '20px', borderRadius: '8px', background: '#e0f7fa' }}>
<h3>React createRef ile D3.js Grafik Entegrasyonu</h3>
<p>Bu veri görselleştirmesi, React tarafından yönetilen bir konteyner içinde D3.js tarafından render edilir.</p>
<div ref={this.chartContainerRef} /> // D3.js bu div içine render edecek
<p><em>Bu tür özel kütüphaneleri entegre etmek, veri ağırlıklı uygulamalar için kritik öneme sahiptir ve çeşitli endüstrilerdeki ve bölgelerdeki kullanıcılara güçlü analitik araçlar sunar.</em></p>
</div>
);
}
}
Bu kapsamlı örnek, bir D3.js çubuk grafiğinin bir React sınıf bileşeni içinde entegrasyonunu göstermektedir. chartContainerRef, D3.js'e render işlemini gerçekleştirmesi için ihtiyaç duyduğu belirli DOM düğümünü sağlar. React, konteyner <div>'in yaşam döngüsünü yönetirken, D3.js kendi iç içeriğini yönetir. `componentDidUpdate` ve `componentWillUnmount` metotları, veri değiştiğinde grafiği güncellemek ve gerekli temizliği yapmak, bellek sızıntılarını önlemek ve duyarlı bir deneyim sağlamak için hayati önem taşır. Bu desen evrensel olarak uygulanabilir olup, geliştiricilerin küresel panolar ve analitik platformlar için hem React'in bileşen modelinin en iyilerinden hem de özel, yüksek performanslı görselleştirme kütüphanelerinden yararlanmalarını sağlar.
4. Dinamik Düzenler için Eleman Boyutlarını veya Konumunu Ölçme
Son derece dinamik veya duyarlı düzenler için veya yalnızca görünür öğeleri render eden sanallaştırılmış listeler gibi özellikleri uygulamak için, elemanların kesin boyutlarını ve konumunu bilmek kritik öneme sahiptir. Ref'ler, bu önemli bilgiyi doğrudan DOM'dan sağlayan getBoundingClientRect() metoduna erişmenizi sağlar.
import React from 'react';
class ElementDimensionLogger extends React.Component {
constructor(props) {
super(props);
this.measurableDivRef = React.createRef();
this.state = {
width: 0,
height: 0,
top: 0,
left: 0,
message: 'Ölçmek için düğmeye tıklayın!'
};
}
componentDidMount() {
// İlk ölçüm genellikle kullanışlıdır, ancak kullanıcı eylemiyle de tetiklenebilir
this.measureElement();
// Dinamik düzenler için, pencere yeniden boyutlandırma olaylarını dinleyebilirsiniz
window.addEventListener('resize', this.measureElement);
}
componentWillUnmount() {
window.removeEventListener('resize', this.measureElement);
}
measureElement = () => {
if (this.measurableDivRef.current) {
const rect = this.measurableDivRef.current.getBoundingClientRect();
this.setState({
width: Math.round(rect.width),
height: Math.round(rect.height),
top: Math.round(rect.top),
left: Math.round(rect.left),
message: 'Boyutlar güncellendi.'
});
} else {
this.setState({ message: 'Eleman henüz render edilmedi.' });
}
};
render() {
const { width, height, top, left, message } = this.state;
const boxStyle = {
width: '70%',
minHeight: '150px',
border: '3px solid #ffc107',
margin: '25px auto',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
background: '#fff3cd',
borderRadius: '8px',
textAlign: 'center'
};
return (
<div style={{ maxWidth: '700px', margin: '30px auto', padding: '25px', boxShadow: '0 4px 12px rgba(0,0,0,0.08)', borderRadius: '10px', background: 'white' }}>
<h3>createRef ile Eleman Boyutlarını Ölçme</h3>
<p>Bu örnek, bir hedef elemanın boyutunu ve konumunu dinamik olarak alır ve görüntüler.</p>
<div ref={this.measurableDivRef} style={boxStyle}>
<p><strong>Ölçülen eleman benim.</strong></p>
<p>Tarayıcı pencerenizi yeniden boyutlandırarak ölçümlerin yenileme/manuel tetikleme ile değiştiğini görün.</p>
</div>
<button
onClick={this.measureElement}
style={{ padding: '10px 20px', background: '#6c757d', color: 'white', border: 'none', borderRadius: '5px', cursor: 'pointer', marginBottom: '15px' }}
>
Şimdi Ölç
</button>
<div style={{ background: '#f0f0f0', padding: '15px', borderRadius: '6px' }}>
<p><strong>Canlı Boyutlar:</strong></p>
<ul style={{ listStyleType: 'none', padding: 0, textAlign: 'left', margin: '0 auto', maxWidth: '300px' }}>
<li>Genişlik: <b>{width}px</b></li>
<li>Yükseklik: <b>{height}px</b></li>
<li>Üst Konum (Viewport): <b>{top}px</b></li>
<li>Sol Konum (Viewport): <b>{left}px</b></li>
</ul>
<p><em>Doğru eleman ölçümü, duyarlı tasarımlar ve dünya genelindeki çeşitli cihazlarda performansı optimize etmek için kritik öneme sahiptir.</em></p>
</div>
</div>
);
}
}
Bu bileşen, bir div elemanının getBoundingClientRect()'ini almak için createRef kullanır ve gerçek zamanlı boyutlarını ve konumunu sağlar. Bu bilgi, karmaşık düzen ayarlamalarını uygulamak, sanallaştırılmış bir kaydırma listesindeki görünürlüğü belirlemek veya hatta elemanların belirli bir viewport alanı içinde olduğundan emin olmak için paha biçilmezdir. Ekran boyutları, çözünürlükler ve tarayıcı ortamlarının çılgınca değiştiği küresel bir kitle için, gerçek DOM ölçümlerine dayalı hassas düzen kontrolü, tutarlı ve yüksek kaliteli bir kullanıcı deneyimi sunmada kilit bir faktördür.
`createRef` Kullanımı için En İyi Uygulamalar ve Uyarılar
createRef güçlü bir zorunlu kontrol sunarken, yanlış kullanımı yönetimi ve hata ayıklaması zor kodlara yol açabilir. Gücünü sorumlu bir şekilde kullanmak için en iyi uygulamalara uymak esastır.
1. Bildirimsel Yaklaşımlara Öncelik Verin: Altın Kural
Her zaman ref'lerin React'teki birincil etkileşim modu değil, bir "kaçış kapısı" olduğunu unutmayın. Bir ref'e uzanmadan önce kendinize sorun: Bu, state ve prop'larla başarılabilir mi? Cevap evet ise, bu neredeyse her zaman daha iyi, daha "React-idiomatik" bir yaklaşımdır. Örneğin, bir girdinin değerini değiştirmek istiyorsanız, doğrudan inputRef.current.value ayarlamak için bir ref değil, state ile kontrollü bileşenler kullanın.
2. Ref'ler Durum Yönetimi İçin Değil, Zorunlu Etkileşimler İçindir
Ref'ler, DOM elemanları veya bileşen örnekleri üzerinde doğrudan, zorunlu eylemler içeren görevler için en uygunudur. Onlar komutlardır: "bu girişe odaklan", "bu videoyu oynat", "bu bölüme kaydır". Bir bileşenin bildirimsel kullanıcı arayüzünü duruma göre değiştirmek için tasarlanmamışlardır. Prop'lar veya state tarafından kontrol edilebilecek bir elemanın stilini veya içeriğini bir ref aracılığıyla doğrudan manipüle etmek, React'in sanal DOM'unun gerçek DOM ile senkronizasyon dışı kalmasına neden olabilir, bu da öngörülemeyen davranışlara ve render sorunlarına yol açar.
3. Ref'ler ve Fonksiyonel Bileşenler: `useRef` ve `forwardRef`'i Benimseyin
Fonksiyonel bileşenler içindeki modern React geliştirmesi için, React.createRef() kullanacağınız araç değildir. Bunun yerine, useRef hook'una güveneceksiniz. useRef hook'u, createRef'e benzer, .current özelliği aynı zorunlu etkileşimler için kullanılabilen değiştirilebilir bir ref nesnesi sağlar. Bileşen yeniden render edildiğinde değerini korur ve kendisi bir yeniden render'a neden olmaz, bu da onu bir DOM düğümüne veya render'lar arasında kalması gereken herhangi bir değiştirilebilir değere bir referans tutmak için mükemmel kılar.
import React, { useRef, useEffect } from 'react';
function FunctionalComponentWithRef() {
const myInputRef = useRef(null); // null ile başlatın
useEffect(() => {
// Bu, bileşen mount olduktan sonra çalışır
if (myInputRef.current) {
myInputRef.current.focus();
console.log('Fonksiyonel bileşen girişi odaklandı!');
}
}, []); // Boş bağımlılık dizisi, yalnızca mount'ta bir kez çalışmasını sağlar
const handleLogValue = () => {
if (myInputRef.current) {
alert(`Input değeri: ${myInputRef.current.value}`);
}
};
return (
<div style={{ margin: '20px', padding: '20px', border: '1px solid #009688', borderRadius: '8px', background: '#e0f2f1' }}>
<h3>Fonksiyonel Bir Bileşende useRef Kullanımı</h3>
<label htmlFor="funcInput">Bir şeyler yazın:</label><br />
<input id="funcInput" type="text" ref={myInputRef} placeholder="Otomatik odaklandım!" style={{ padding: '8px', margin: '10px 0', borderRadius: '4px', border: '1px solid #ccc' }} /><br />
<button onClick={handleLogValue} style={{ padding: '10px 15px', background: '#009688', color: 'white', border: 'none', borderRadius: '5px', cursor: 'pointer' }}>
Input Değerini Logla
</button>
<p><em>Yeni projeler için, `useRef` fonksiyonel bileşenlerdeki ref'ler için deyimsel bir seçimdir.</em></p>
</div>
);
}
Bir ebeveyn bileşenin bir fonksiyonel alt bileşen içindeki bir DOM elemanına bir ref alması gerekiyorsa, çözümünüz React.forwardRef'tir. Bu, bir ref'i bir ebeveynden alt elemanlarından birinin DOM elemanına "iletmenize" olanak tanıyan, fonksiyonel bileşenin kapsüllenmesini korurken gerektiğinde zorunlu erişimi sağlayan üst düzey bir bileşendir.
import React, { useRef, useEffect } from 'react';
// Bir ref'i açıkça yerel input elemanına ileten fonksiyonel bileşen
const ForwardedInput = React.forwardRef((props, ref) => (
<input type="text" ref={ref} className="forwarded-input" placeholder={props.placeholder} style={{ padding: '10px', margin: '8px 0', border: '1px solid #ccc', borderRadius: '4px', width: '100%' }} />
));
class ParentComponentUsingForwardRef extends React.Component {
constructor(props) {
super(props);
this.parentInputRef = React.createRef();
}
componentDidMount() {
if (this.parentInputRef.current) {
this.parentInputRef.current.focus();
console.log('Fonksiyonel bileşen içindeki input, ebeveynden (sınıf bileşeni) iletilen ref aracılığıyla odaklandı!');
}
}
render() {
return (
<div style={{ margin: '20px', padding: '20px', border: '1px solid #6f42c1', borderRadius: '8px', background: '#f5eef9' }}>
<h3>createRef ile Ref İletme Örneği (Ebeveyn Sınıf Bileşeni)</h3>
<label>Detayları girin:</label>
<ForwardedInput ref={this.parentInputRef} placeholder="Bu input bir fonksiyonel bileşenin içinde" />
<p><em>Bu desen, doğrudan DOM erişimini açığa çıkarması gereken yeniden kullanılabilir bileşen kütüphaneleri oluşturmak için çok önemlidir.</em></p>
</div>
);
}
}
Bu, createRef kullanan bir sınıf bileşenin, forwardRef'ten yararlanarak bir fonksiyonel bileşen içine yuvalanmış bir DOM elemanıyla etkili bir şekilde nasıl etkileşim kurabileceğini gösterir. Bu, modern React kod tabanlarının hala ref'lerden faydalanabilmesini sağlarken, fonksiyonel bileşenleri gerektiğinde zorunlu etkileşimlere katılma konusunda eşit derecede yetenekli hale getirir.
4. Ref'leri Ne Zaman Kullanmamalı: React'in Bütünlüğünü Koruma
- Alt bileşen durumunu kontrol etmek için: Bir alt bileşenin durumunu doğrudan okumak veya güncellemek için asla bir ref kullanmayın. Bu, React'in durum yönetimini atlar ve uygulamanızı öngörülemez hale getirir. Bunun yerine, durumu prop olarak aşağı geçirin ve çocukların ebeveynlerden durum değişiklikleri talep etmesine izin vermek için callback'ler kullanın.
- Prop'ların yerine: Bir ref aracılığıyla bir alt sınıf bileşeninde metotları çağırabilseniz de, çocuğa bir olay işleyiciyi prop olarak geçmenin aynı amaca daha "React-idiomatik" bir şekilde ulaşıp ulaşmayacağını düşünün. Prop'lar net veri akışını teşvik eder ve bileşen etkileşimlerini şeffaf hale getirir.
-
React'in halledebileceği basit DOM manipülasyonları için: Bir elemanın metnini, stilini değiştirmek veya duruma göre bir sınıf eklemek/kaldırmak istiyorsanız, bunu bildirimsel olarak yapın. Örneğin, bir
activesınıfını değiştirmek için,divRef.current.classList.add('active')yerine JSX'te koşullu olarak uygulayın:<div className={isActive ? 'active' : ''}>.
5. Performans Düşünceleri ve Küresel Erişim
createRef'in kendisi performanslı olsa da, current kullanılarak gerçekleştirilen işlemlerin önemli performans etkileri olabilir. Düşük donanımlı cihazlardaki veya yavaş ağ bağlantılarındaki kullanıcılar için (dünyanın birçok yerinde yaygın), verimsiz DOM manipülasyonları takılmalara, tepkisiz kullanıcı arayüzlerine ve kötü bir kullanıcı deneyimine yol açabilir. Animasyonlar, karmaşık düzen hesaplamaları veya ağır üçüncü taraf kütüphaneleri entegre etmek gibi görevler için ref kullanırken:
-
Olayları Debounce/Throttle Edin:
window.resizeveyascrollolaylarında boyutları ölçmek için ref kullanıyorsanız, aşırı işlev çağrılarını ve DOM okumalarını önlemek için bu işleyicilerin debounce veya throttle edildiğinden emin olun. -
DOM Okuma/Yazma İşlemlerini Toplu Hale Getirin: DOM okuma işlemlerini (örneğin,
getBoundingClientRect()) DOM yazma işlemleriyle (örneğin, stilleri ayarlama) iç içe geçirmekten kaçının. Bu, layout thrashing'e (düzen sarsıntısı) neden olabilir.fastdomgibi araçlar bunu verimli bir şekilde yönetmenize yardımcı olabilir. -
Kritik Olmayan İşlemleri Erteleyin: Ana iş parçacığını engellememelerini ve duyarlılığı etkilememelerini sağlamak için animasyonlar için
requestAnimationFrameve daha az kritik DOM manipülasyonları içinsetTimeout(..., 0)veyarequestIdleCallbackkullanın. - Akıllıca Seçim Yapın: Bazen, bir üçüncü taraf kütüphanesinin performansı bir darboğaz olabilir. Alternatifleri değerlendirin veya yavaş bağlantılardaki kullanıcılar için bu tür bileşenleri tembel yüklemeyi (lazy-loading) düşünün, böylece temel bir deneyimin küresel olarak performanslı kalmasını sağlayın.
`createRef`, Callback Ref'ler ve `useRef` Karşılaştırması
React, evrimi boyunca ref'leri yönetmek için farklı yollar sunmuştur. Her birinin nüanslarını anlamak, özel bağlamınız için en uygun yöntemi seçmenin anahtarıdır.
1. `React.createRef()` (Sınıf Bileşenleri - Modern)
-
Mekanizma: Bileşen örneğinin constructor'ında bir ref nesnesi (
{ current: null }) oluşturur. React, mount edildikten sonra DOM elemanını veya bileşen örneğini.currentözelliğine atar. - Birincil Kullanım: Yalnızca sınıf bileşenleri içinde. Bileşen örneği başına bir kez başlatılır.
-
Ref Doldurma:
.current, bileşen mount olduktan sonra elemana/örneğe ayarlanır ve unmount edildiğindenull'a sıfırlanır. - En İyisi: Bir DOM elemanına veya bir alt sınıf bileşeni örneğine referans vermeniz gereken sınıf bileşenlerindeki tüm standart ref gereksinimleri için.
- Avantajları: Açık, anlaşılır nesne yönelimli sözdizimi. Satır içi fonksiyonun yeniden oluşturulmasının ekstra çağrılara neden olması (callback ref'lerde olabileceği gibi) endişesi yoktur.
- Dezavantajları: Fonksiyonel bileşenlerle kullanılamaz. Constructor'da başlatılmazsa (örneğin, render'da), her render'da yeni bir ref nesnesi oluşturulabilir, bu da potansiyel performans sorunlarına veya yanlış ref değerlerine yol açabilir. Bir örnek özelliğine atamayı hatırlamayı gerektirir.
2. Callback Ref'ler (Sınıf & Fonksiyonel Bileşenler - Esnek/Eski)
-
Mekanizma: Doğrudan
refprop'una bir fonksiyon geçirirsiniz. React bu fonksiyonu mount edilmiş DOM elemanı veya bileşen örneği ile ve daha sonra unmount edildiğindenullile çağırır. -
Birincil Kullanım: Hem sınıf hem de fonksiyonel bileşenlerde kullanılabilir. Sınıf bileşenlerinde, callback genellikle
this'e bağlanır veya bir ok fonksiyonu sınıf özelliği olarak tanımlanır. Fonksiyonel bileşenlerde genellikle satır içi olarak tanımlanır veya memoize edilir. -
Ref Doldurma: Callback fonksiyonu doğrudan React tarafından çağrılır. Referansı saklamaktan siz sorumlusunuz (örneğin,
this.myInput = element;). -
En İyisi: Ref'lerin ne zaman ayarlandığı ve kaldırıldığı üzerinde daha ince taneli kontrol gerektiren senaryolar veya dinamik ref listeleri gibi gelişmiş desenler için.
createRefveuseRef'ten önce ref'leri yönetmenin birincil yoluydu. - Avantajları: Maksimum esneklik sağlar. Ref mevcut olduğunda (callback fonksiyonu içinde) anında erişim sağlar. Dinamik eleman koleksiyonları için ref'leri bir dizide veya haritada saklamak için kullanılabilir.
-
Dezavantajları: Callback,
rendermetodu içinde satır içi olarak tanımlanırsa (örneğin,ref={el => this.myRef = el}), güncellemeler sırasında iki kez çağrılır (bir keznullile, sonra elemanla), bu da dikkatli bir şekilde ele alınmazsa (örneğin, callback'i bir sınıf metodu yaparak veya fonksiyonel bileşenlerdeuseCallbackkullanarak) performans sorunlarına veya beklenmedik yan etkilere neden olabilir.
class CallbackRefDetailedExample extends React.Component {
constructor(props) {
super(props);
this.inputElement = null;
}
// Bu metot, ref'i ayarlamak için React tarafından çağrılacaktır
setInputElementRef = element => {
if (element) {
console.log('Ref elemanı:', element);
}
this.inputElement = element; // Gerçek DOM elemanını sakla
};
componentDidMount() {
if (this.inputElement) {
this.inputElement.focus();
}
}
render() {
return (
<div>
<label>Callback Ref Girişi:</label>
<input type="text" ref={this.setInputElementRef} />
</div>
);
}
}
3. `useRef` Hook'u (Fonksiyonel Bileşenler - Modern)
-
Mekanizma: Değiştirilebilir bir ref nesnesi (
{ current: initialValue }) döndüren bir React Hook'u. Döndürülen nesne, fonksiyonel bileşenin tüm ömrü boyunca kalıcıdır. - Birincil Kullanım: Yalnızca fonksiyonel bileşenler içinde.
-
Ref Doldurma:
createRef'e benzer şekilde, React DOM elemanını veya bileşen örneğini (iletilmişse) mount ettikten sonra.currentözelliğine atar ve unmount'tanull'a ayarlar..currentdeğeri manuel olarak da güncellenebilir. - En İyisi: Fonksiyonel bileşenlerdeki tüm ref yönetimi için. Ayrıca, bir yeniden render tetiklemeden render'lar arasında kalıcı olması gereken herhangi bir değiştirilebilir değeri (örneğin, zamanlayıcı ID'leri, önceki değerler) tutmak için de kullanışlıdır.
- Avantajları: Hook'lar için basit, deyimsel. Ref nesnesi render'lar arasında kalıcıdır, yeniden oluşturma sorunlarını önler. Sadece DOM düğümlerini değil, herhangi bir değiştirilebilir değeri saklayabilir.
-
Dezavantajları: Yalnızca fonksiyonel bileşenlerde çalışır. Yaşam döngüsüyle ilgili ref etkileşimleri için (mount'ta odaklanma gibi) açık
useEffectgerektirir.
Özetle:
-
Bir sınıf bileşeni yazıyorsanız ve bir ref'e ihtiyacınız varsa,
React.createRef()önerilen ve en açık seçimdir. -
Bir fonksiyonel bileşen yazıyorsanız ve bir ref'e ihtiyacınız varsa,
useRefHook'u modern, deyimsel çözümdür. - Callback ref'ler hala geçerlidir ancak genellikle daha ayrıntılıdır ve dikkatli bir şekilde uygulanmazsa ince sorunlara eğilimlidir. Gelişmiş senaryolar için veya hook'ların mevcut olmadığı eski kod tabanları veya bağlamlarla çalışırken kullanışlıdırlar.
-
Ref'leri bileşenler aracılığıyla (özellikle fonksiyonel olanlar) geçirmek için,
React.forwardRef(), genellikle ebeveyn bileşendecreateRefveyauseRefile birlikte kullanılarak esastır.
Küresel Düşünceler ve Ref'lerle Gelişmiş Erişilebilirlik
Genellikle teknik bir boşlukta tartışılsa da, ref'lerin küresel düşünceyle tasarlanmış bir uygulama bağlamında kullanımı, özellikle çeşitli kullanıcılar için performans ve erişilebilirlik açısından önemli sonuçlar doğurur.
1. Çeşitli Cihazlar ve Ağlar için Performans Optimizasyonu
createRef'in kendisinin paket boyutuna etkisi minimaldir, çünkü React çekirdeğinin küçük bir parçasıdır. Ancak, current özelliği ile gerçekleştirdiğiniz işlemlerin önemli performans etkileri olabilir. Düşük donanımlı cihazlardaki veya yavaş ağ bağlantılarındaki kullanıcılar için (dünyanın birçok yerinde yaygın), verimsiz DOM manipülasyonları takılmalara, tepkisiz kullanıcı arayüzlerine ve kötü bir kullanıcı deneyimine yol açabilir. Animasyonlar, karmaşık düzen hesaplamaları veya ağır üçüncü taraf kütüphaneleri entegre etmek gibi görevler için ref kullanırken:
-
Olayları Debounce/Throttle Edin:
window.resizeveyascrollolaylarında boyutları ölçmek için ref kullanıyorsanız, aşırı işlev çağrılarını ve DOM okumalarını önlemek için bu işleyicilerin debounce veya throttle edildiğinden emin olun. -
DOM Okuma/Yazma İşlemlerini Toplu Hale Getirin: DOM okuma işlemlerini (örneğin,
getBoundingClientRect()) DOM yazma işlemleriyle (örneğin, stilleri ayarlama) iç içe geçirmekten kaçının. Bu, layout thrashing'e (düzen sarsıntısı) neden olabilir.fastdomgibi araçlar bunu verimli bir şekilde yönetmenize yardımcı olabilir. -
Kritik Olmayan İşlemleri Erteleyin: Ana iş parçacığını engellememelerini ve duyarlılığı etkilememelerini sağlamak için animasyonlar için
requestAnimationFrameve daha az kritik DOM manipülasyonları içinsetTimeout(..., 0)veyarequestIdleCallbackkullanın. - Akıllıca Seçim Yapın: Bazen, bir üçüncü taraf kütüphanesinin performansı bir darboğaz olabilir. Alternatifleri değerlendirin veya yavaş bağlantılardaki kullanıcılar için bu tür bileşenleri tembel yüklemeyi (lazy-loading) düşünün, böylece temel bir deneyimin küresel olarak performanslı kalmasını sağlayın.
2. Erişilebilirliği Geliştirme (ARIA Nitelikleri ve Klavye Navigasyonu)
Ref'ler, özellikle yerel tarayıcı eşdeğerleri olmayan özel kullanıcı arayüzü bileşenleri oluştururken veya varsayılan davranışları geçersiz kılarken, son derece erişilebilir web uygulamaları oluşturmada etkili bir araçtır. Küresel bir kitle için, Web İçeriği Erişilebilirlik Yönergeleri'ne (WCAG) uymak sadece iyi bir uygulama değil, aynı zamanda genellikle yasal bir gerekliliktir. Ref'ler şunları sağlar:
- Programatik Odak Yönetimi: Giriş alanlarında görüldüğü gibi, ref'ler odak ayarlamanıza olanak tanır, bu da klavye kullanıcıları ve ekran okuyucu navigasyonu için çok önemlidir. Bu, modallar, açılır menüler veya etkileşimli widget'lar içindeki odağı yönetmeyi içerir.
-
Dinamik ARIA Nitelikleri: DOM elemanlarına dinamik olarak ARIA (Accessible Rich Internet Applications) nitelikleri (örneğin,
aria-expanded,aria-controls,aria-live) eklemek veya güncellemek için ref'leri kullanabilirsiniz. Bu, tek başına görsel kullanıcı arayüzünden çıkarılamayabilecek anlamsal bilgileri yardımcı teknolojilere sağlar.class CollapsibleSection extends React.Component {
constructor(props) {
super(props);
this.buttonRef = React.createRef();
this.state = { isExpanded: false };
}
toggleExpanded = () => {
this.setState(prevState => ({ isExpanded: !prevState.isExpanded }), () => {
if (this.buttonRef.current) {
// Duruma göre ARIA niteliğini dinamik olarak güncelle
this.buttonRef.current.setAttribute('aria-expanded', this.state.isExpanded);
}
});
};
componentDidMount() {
if (this.buttonRef.current) {
this.buttonRef.current.setAttribute('aria-controls', `section-${this.props.id}`);
this.buttonRef.current.setAttribute('aria-expanded', this.state.isExpanded);
}
}
render() {
const { id, title, children } = this.props;
const { isExpanded } = this.state;
return (
<div style={{ margin: '20px auto', maxWidth: '600px', border: '1px solid #0056b3', borderRadius: '8px', background: '#e7f0fa', overflow: 'hidden' }}>
<h4>
<button
ref={this.buttonRef} // ARIA nitelikleri için düğmeye ref
onClick={this.toggleExpanded}
style={{ background: 'none', border: 'none', padding: '15px 20px', width: '100%', textAlign: 'left', cursor: 'pointer', fontSize: '1.2em', color: '#0056b3', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}
id={`section-header-${id}`}
>
{title} <span>▼</span>
</button>
</h4>
{isExpanded && (
<div id={`section-${id}`} role="region" aria-labelledby={`section-header-${id}`} style={{ padding: '0 20px 20px', borderTop: '1px solid #a7d9f7' }}>
{children}
</div>
)}
</div>
);
}
} - Klavye Etkileşim Kontrolü: Özel açılır menüler, kaydırıcılar veya diğer etkileşimli elemanlar için, belirli klavye olay işleyicilerini (örneğin, bir liste içinde gezinmek için ok tuşları) uygulamanız gerekebilir. Ref'ler, bu olay dinleyicilerinin eklenebileceği ve yönetilebileceği hedef DOM elemanına erişim sağlar.
Ref'leri düşünceli bir şekilde uygulayarak, geliştiriciler uygulamalarının dünya çapında engelli insanlar için kullanılabilir ve kapsayıcı olmasını sağlayabilir, böylece küresel erişimlerini ve etkilerini büyük ölçüde genişletebilirler.
3. Uluslararasılaştırma (I18n) ve Yerelleştirilmiş Etkileşimler
Uluslararasılaştırma (i18n) ile çalışırken, ref'ler ince ama önemli bir rol oynayabilir. Örneğin, Sağdan Sola (RTL) bir alfabe kullanan dillerde (Arapça, İbranice veya Farsça gibi), doğal sekme sırası ve kaydırma yönü Soldan Sağa (LTR) dillerden farklı olabilir. Ref'leri kullanarak odaklanmayı veya kaydırmayı programatik olarak yönetiyorsanız, mantığınızın belgenin veya elemanın metin yönünü (dir niteliği) dikkate aldığından emin olmak çok önemlidir.
- RTL Uyumlu Odak Yönetimi: Tarayıcılar genellikle RTL için varsayılan sekme sırasını doğru bir şekilde ele alsa da, özel odak tuzakları veya sıralı odaklanma uyguluyorsanız, tutarlı ve sezgisel bir deneyim sağlamak için ref tabanlı mantığınızı RTL ortamlarında kapsamlı bir şekilde test edin.
-
RTL'de Düzen Ölçümü: Bir ref aracılığıyla
getBoundingClientRect()kullanırken,leftverightözelliklerinin viewport'a göre olduğunu unutmayın. Görsel başlangıç/bitişe bağlı düzen hesaplamaları için, mantığınızı RTL düzenleri için ayarlamak üzeredocument.dirveya elemanın hesaplanmış stilini göz önünde bulundurun. - Üçüncü Taraf Kütüphane Entegrasyonu: Ref'ler aracılığıyla entegre edilen herhangi bir üçüncü taraf kütüphanenin (örneğin, grafik kütüphaneleri) kendilerinin i18n uyumlu olduğundan ve uygulamanız destekliyorsa RTL düzenlerini doğru bir şekilde ele aldığından emin olun. Bunu sağlama sorumluluğu genellikle kütüphaneyi bir React bileşenine entegre eden geliştiriciye düşer.
Sonuç: Küresel Uygulamalar için `createRef` ile Zorunlu Kontrolde Ustalaşma
React.createRef(), React'te sadece bir "kaçış kapısı"ndan daha fazlasıdır; React'in güçlü bildirimsel paradigması ile tarayıcı DOM etkileşimlerinin zorunlu gerçekleri arasındaki boşluğu dolduran hayati bir araçtır. Yeni fonksiyonel bileşenlerdeki rolü büyük ölçüde useRef hook'u tarafından devralınmış olsa da, createRef, hala dünya çapında birçok kurumsal uygulamanın önemli bir bölümünü oluşturan sınıf bileşenleri içinde ref'leri yönetmenin standart ve en deyimsel yolu olmaya devam etmektedir.
Oluşturulmasını, eklenmesini ve .current özelliğinin kritik rolünü tam olarak anlayarak, geliştiriciler programatik odak yönetimi, doğrudan medya kontrolü, çeşitli üçüncü taraf kütüphanelerle (D3.js grafiklerinden özel zengin metin düzenleyicilerine kadar) sorunsuz entegrasyon ve hassas eleman boyut ölçümü gibi zorlukların üstesinden güvenle gelebilirler. Bu yetenekler sadece teknik başarılar değil; küresel kullanıcıların, cihazların ve kültürel bağlamların geniş bir yelpazesinde performanslı, erişilebilir ve kullanıcı dostu uygulamalar oluşturmak için temeldir.
Bu gücü akıllıca kullanmayı unutmayın. Her zaman önce React'in bildirimsel state ve prop sistemini tercih edin. Zorunlu kontrol gerçekten gerektiğinde, createRef (sınıf bileşenleri için) veya useRef (fonksiyonel bileşenler için) bunu başarmak için sağlam ve iyi tanımlanmış bir mekanizma sunar. Ref'lerde ustalaşmak, modern web geliştirmenin uç durumlarını ve inceliklerini ele almanızı sağlar, böylece React uygulamalarınızın dünyanın her yerinde olağanüstü kullanıcı deneyimleri sunmasını sağlarken, React'in zarif bileşen tabanlı mimarisinin temel faydalarını korur.
İleri Okuma ve Keşif
- React Resmi Ref Dökümantasyonu: En güncel bilgi için doğrudan kaynaktan danışın: <em>https://react.dev/learn/manipulating-the-dom-with-refs</em>
- React'in `useRef` Hook'unu Anlamak: Fonksiyonel bileşen eşdeğerine daha derinlemesine dalmak için keşfedin: <em>https://react.dev/reference/react/useRef</em>
- `forwardRef` ile Ref İletme: Ref'leri bileşenler aracılığıyla etkili bir şekilde nasıl geçireceğinizi öğrenin: <em>https://react.dev/reference/react/forwardRef</em>
- Web İçeriği Erişilebilirlik Yönergeleri (WCAG): Küresel web geliştirme için temel: <em>https://www.w3.org/WAI/WCAG22/quickref/</em>
- React Performans Optimizasyonu: Yüksek performanslı uygulamalar için en iyi pratikler: <em>https://react.dev/learn/optimizing-performance</em>